<?php
import('libs.auth.AntiBruteForce');

$_SESSION['back2'] = @$_SESSION['back'];
$_SESSION['back'] = @$_SERVER['HTTP_REFERER'];
/**
 * La classe Session. Elle permet de se connecter et de se déconnecter, de lister les membres en lignes et de récupérer les infos du visiteur.
 * La création des tables est décrite en bas du document
 * @author Gaétan Collaud
 */
class Session
{
	private $default = array(
		'id'		=> 0,
		'user_name'	=> '',
		'droit'		=> 0);

	private $const = array();

	private $connecte = false;		//s'il est connecté
	private $infos = array();		//infos sur le membre
	private $nb_ligne = 0;			//nb de personne connecte

	private $cookies_expire = 0;
	private $session_expire = 0;

	const SERIALISEDFILE = 'cache/session.ser';

	/**
	* Constructeur.
	* Définit les timeout, recupere les infos du membre et recupere les membres connecté
	*/
	public function __construct() {
		$this->cookies_expire = COOKIES*24*3600+time();
		$this->session_expire = 15*60;//15min

		$this->recup_infos();
		$this->listConnecte();
	}

	/**
	* Définit les constantes en fonction des infos du membre
	*/
	public function createConstantes(){
		foreach($this->const as $k)
		define(strtoupper($k), $this->infos[$k]);
	}

	/**
	 * Crée et retourne un tableau associatif des droits de sorte à ce qu'ils soient accessibles depuis les templates
	 * @return Array le tableau des droits
	 */
	public function getDroits(){
		$r = array();
		$d = &$this->infos['droit'];
		$r['membre']	= (bool)($d&1);
		return $r;
	}

	/**
	* Récupère les infos et remplis $infos
	*/
	private function recup_infos(){
		if(!isset($_SESSION['connecte'])){
			if(isset($_COOKIE['login_auto']) && $_COOKIE['login_auto']==1) $this->connect_auto();
			else $this->infos = $this->default;
		}else{
			$this->infos = $_SESSION['infos'];
			$this->connecte = $_SESSION['connecte'];
		}

		$this->define_infos();
	}

	/**
	* Met les infos en session pour la prochaine page
	*/
	private function define_infos(){
		$this->infos['sid'] = @$_COOKIE['PHPSESSID'];
		$this->infos['ip'] = $this->ip();
		$_SESSION['connecte'] = $this->connecte;
		$_SESSION['infos'] = $this->infos;
	}


	/**
	* Récupère les connectés, met à jour ou ajoute le membre en cours et supprimer les membres qui se sont partis.
	*/
	private function listConnecte() {
		$ajoute = false;
		$time = time()-$this->session_expire;
		$file = ABS_DIR.self::SERIALISEDFILE;

		if(is_file($file)) $listConnecte = unserialize(file_get_contents($file));
		else $listConnecte = array();

		foreach($listConnecte as $k => $d){
			if($d['time'] < $time && $this->infos['sid'] != $k || empty($k)) unset($listConnecte[$this->infos['sid']]);
			else ++$this->nb_ligne;

			if($k == $this->infos['sid'])
			--$this->nb_ligne;
		}

		$listConnecte[$this->infos['sid']]['time'] = time();
		$listConnecte[$this->infos['sid']]['fk_membre'] = $this->infos['id'];
		++$this->nb_ligne;

		file_put_contents($file, serialize($listConnecte));
	}

	/**
	* Lors de la première page chargée, vérifie si le membre doit Ãªtre connecté automatiquement et le connecte au besoin.
	*/
	private function connect_auto() {
		if($this->connexion($_COOKIE['user_name'], $_COOKIE['pass'], true, true)){
			setcookie('login_auto', 0, $this->cookies_expire, '/');
			$this->infos = $this->default;
		}
	}

	/**
	* Connecte le membre
	* @param $pseudo	pseudo du membre
	* @param $pass		pass du membre
	* @param $log_auto	si le membre veut un cookies pour se connecté automatiquement
	* @param $is_md5	si le mot de pass est déjà en MD5
	* @return 'ok' s'il n'y a aucune erreur, sinon un string définissant l'erreur.
	*/
	public function connexion($user_name, $pass, $log_auto = false, $is_md5 = false) {
		if(AntiBruteForce::estBloque($user_name)) return 'bloque';
		if(!AntiBruteForce::estAutorise($user_name)) return 'tentative';

		$md5_pass = $is_md5 ? $pass : md5($pass);
		$ret = 'ok';

		$res = Base::getSql()->query("SELECT m.pk_user, m.pass, m.user_name, n.droit
		FROM t_users AS m
		INNER JOIN t_groups AS n USING(pk_group)
		WHERE m.user_name='".Base::getSql()->escape($user_name)."' LIMIT 1");

		if($res->noResult()) $ret = 'user_name';
		else{
			$d = $res->fetch();

			if($d['pass'] != $md5_pass) $ret = 'pass';
			else{
				$this->infos = array(
				'id' => (int)$d['pk_user'],
				'user_name' => $d['user_name'],
				'droit' => (int)$d['droit']);

				$this->connecte = true;
				$this->define_infos();

				if($log_auto) {
					setcookie('user_name', $user_name, $this->cookies_expire, '/');
					setcookie('pass', $md5_pass, $this->cookies_expire, '/');
					setcookie('login_auto', 1, $this->cookies_expire, '/');
				}
			}
		}

		if($ret=='ok') AntiBruteForce::connexionReussie($user_name);
		else AntiBruteForce::connexionEchouee($user_name);
		
		return $ret;
	}

	/**
	* Permet au membre de se deconnecter
	* remet les infos par défaut
	*/
	public function deconnexion() {
		session_destroy();
		setcookie('login_auto', '0', $this->cookies_expire, '/');
		$this->infos = $this->default;
	}

	/**
	* Récupère l'ip du membre (avec proxy)
	* @return adresse ip du visiteur
	*/
	private function ip() {
		if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
			$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		elseif(isset($_SERVER['HTTP_CLIENT_IP']))
			$ip = $_SERVER['HTTP_CLIENT_IP'];
		else
			$ip = $_SERVER['REMOTE_ADDR'];

		return $ip;
	}

	/**
	 * Verifie si l'utilisateur à les droits pour visiter une page, sinon redirection.
	 * @param Mixed $nom le nom du droit ou le droit en binaire
	 * @param boolean $bin si le droit et donné en binaire.
	 */
	public function verif($nom, $bin=true){
		if(!$this->connecte) {
			header('Location: '.URL_DIR.'membre/connexion');
		}else{
			if(!$this->droit($nom, $bin)) Erreur::rang();
		}
	}
	/**
	 * Retourne truc si l'utilisateur à le droit de visiter une page
	 * @param Mixed $nom le nom du droit ou le droit en binaire
	 * @param boolean $bin si le droit et donné en binaire.
	 * @return boolean true si l'utilisateur à les droits
	 */
	public function droit($nom, $bin=false){
		if($bin){ if(is_string($nom)) $d = bindec($nom); }
		else{ $ar = $this->getDroits(); $d = $ar[$nom]; }
		return ($this->infos['droit']&$d) != 0;
	}

	/**
	* Accesseur à la propriété $connecte
	* @return true si le visiteur est connecté
	*/
	public function isConnecte(){
		return $this->connecte;
	}

	/**
	* Accesseur aux infos du membre
	* @param $n	la clé du tableau associatif
	* @return l'information demandée
	*/
	public function __get($n){
		if(isset($this->infos[$n])) return $this->infos[$n];
		exit('Sesssion : information <b>'.$n.'</b> non déclarée');
	}

	/**
	* Accesseur au nombre de personne en ligne
	* @return le nombre de personne en ligne actuellement
	*/
	public function getNbLigne(){
		return $this->nb_ligne;
	}

	/**
	* Accesseur à la liste des membres en ligne
	* @return un tableau avec la liste des membre en ligne
	*/
	public function getMLigne(){
		return $this->m_ligne;
	}

	public function isAdmin(){
		return $this->infos['droit']>1;
	}
}

/**
 * Création des tables :
--------------------------------------------------------------
Create table t_users (
	pk_user Int NOT NULL AUTO_INCREMENT,
	user_name Varchar(30) NOT NULL,
	pass Varchar(32) NOT NULL,
	pk_group Int NOT NULL,
 Primary Key (pk_user)) ENGINE = InnoDB;
Create table t_groups (
	pk_group Int NOT NULL AUTO_INCREMENT,
	name Varchar(30) NOT NULL,
	droit Int UNSIGNED NOT NULL DEFAULT 1,
 Primary Key (pk_group)) ENGINE = InnoDB;
Alter table t_users add Foreign Key (pk_group) references t_groups (pk_group) on delete  restrict on update  restrict;
--------------------------------------------------------------
 */

?>